package com.jtny.nytb.equipment.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.jtny.component.entity.LocalHolder;
import com.jtny.component.util.Assert;
import com.jtny.component.util.BeanUtils;

import com.jtny.nytb.config.datafactor.dto.DataParam4EquipmentDTO;

import com.jtny.nytb.config.datafactor.service.DataParamEquipmentExtendService;
import com.jtny.nytb.equipment.dto.ModelDTO;
import com.jtny.nytb.equipment.vo.typeAndArea.DeviceAreaResponseVO;
import com.jtny.nytb.equipment.dto.dataparam.AlarmTempDTO;
import com.jtny.nytb.equipment.dto.dataparam.AlgorithmTempDTO;
import com.jtny.nytb.equipment.dto.dataparam.DataParamTempDTO;
import com.jtny.nytb.equipment.dto.device.EquipmentExcelDTO;
import com.jtny.nytb.equipment.dto.device.EquipmentInfoDTO;
import com.jtny.nytb.equipment.dto.excel.*;
import com.jtny.nytb.equipment.dto.instrument.ResponseInstrumentDTO;
import com.jtny.nytb.equipment.dto.model.ExcelModelDTO;
import com.jtny.nytb.equipment.dto.model.ModelInfoDTO;
import com.jtny.nytb.equipment.enums.CodeRuleTypeEnum;
import com.jtny.nytb.equipment.enums.DataParamImportEnum;
import com.jtny.nytb.property.CodeProperty;
import com.jtny.nytb.equipment.service.*;
import com.jtny.nytb.equipment.vo.dataparam.AlgorithmExcelVO;
import com.jtny.nytb.equipment.vo.dataparam.DataParamTempVO;
import com.jtny.nytb.equipment.vo.excel.*;
import com.jtny.nytb.equipment.vo.excel.utils.ExcelSheetVO;
import com.jtny.nytb.equipment.vo.model.EquipmentModelParamExcelVO;
import lombok.AllArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author 智慧能源中心 - 伍天宇
 * @package com.jtny.nytb.equipment.biz.impl
 * @fileName ImportExcelBizImpl.java
 * @createTime 2023年10月12日 17:55
 * @Copyright© 2023 jtny
 * 江投能源技术研究院 版权所有
 */
@Service
@AllArgsConstructor
public class ImportExcelServiceImpl implements ImportExcelService {
    private DeviceAreaService deviceAreaService;
    private EquipmentModelService equipmentModelService;
    private DataParamTempService dataParamTempService;
    private EquipmentInfoExtraService equipmentInfoExtraService;
    private DataParamService dataParamService;
    private InstrumentExtraService instrumentBiz;
    private RedisService redis;
    private ExcelService excelClient;

    /**
     * 导入模型 redis 缓存版
     *
     * @param excelSheetList Excel工作表列表
     * @param type           类型
     * @param map
     * @return {@link ExcelResultVO}
     */
    @Override
    public ExcelResultVO importModelExcel(DataParamImportEnum type, Map<Class<?>, List<?>> map, List<ExcelSheetVO> excelSheetList) {
        redis.deleteRedisCleanAll();
        Long userId = LocalHolder.getCurrentUser().getUserId();
        for (int i = 0; i < excelSheetList.size(); i++) {
            importModelPref(i, type, excelSheetList, map);
            // 使用redis 缓存优先  参量数据缓存到redis
            importDataParamInfo(i, excelSheetList, map, DataParamImportEnum.MODEL);
        }
        List<ExcelModelDTO> toSaveBatch = redis.listAllExcelModel();
        // 保存数据 key: 设备名称 value: 设备信息
        // 获取导入错误信息
        ExcelResultVO excelResultVO = redis.getExcelResult(userId);
        excelResultVO.setSuccessCount(toSaveBatch.size());
        if (CollUtil.isNotEmpty(toSaveBatch)) {
            toSaveModel(toSaveBatch,map,type);
        }
        return excelResultVO;
    }

    @Async
    public void toSaveModel(List<ExcelModelDTO> toSaveBatch, Map<Class<?>, List<?>> map, DataParamImportEnum type) {
        Map<String, ModelDTO> mapModelName = excelClient.importExcelModel(toSaveBatch);
        // 对已经封装好的参量 持久化操作
        toImportDataParamTemp(mapModelName,map,type);
//        redis.deleteRedisCleanAll();
    }


    /**
     * 导入模型
     *
     * @param target         目标
     * @param type           类型
     * @param excelSheetList Excel 工作表列表
     * @param map            地图
     * @return {@link Boolean}
     */
    private void importModelPref(Integer target, DataParamImportEnum type, List<ExcelSheetVO> excelSheetList, Map<Class<?>, List<?>> map) {
        if (excelSheetList.get(target).getClazz().equals(ExcelModelVO.class)) {
            List<ExcelModelVO> modelList = BeanUtils.copyToList(map.get(ExcelModelVO.class), ExcelModelVO.class);
            validateDuplicateModelName(modelList);
            List<ExcelModelDTO> excelEquipmentDTOS = cleanModel(type, modelList);
            redis.setAllExcelModel(excelEquipmentDTOS);
        }
        if (excelSheetList.get(target).getClazz().equals(EquipmentModelParamExcelVO.class)) {
            List<EquipmentModelParamExcelVO> equipmentModelParamList =
                    BeanUtils.copyToList(map.get(EquipmentModelParamExcelVO.class), EquipmentModelParamExcelVO.class);
            setAllRedisKey4Param(equipmentModelParamList);
        }
    }

    /**
     * 导入设备 Excel 增强
     *
     * @param type           类型
     * @param map            地图
     * @param excelSheetList Excel 工作表列表
     * @return {@link ExcelResultVO}
     */
    @Override
    public ExcelResultVO importEquipmentExcel(DataParamImportEnum type,
                                              Map<Class<?>, List<?>> map,
                                              List<ExcelSheetVO> excelSheetList) {
        redis.deleteRedisCleanAll();
        Long userId = LocalHolder.getCurrentUser().getUserId();
        for (int i = 0; i < excelSheetList.size(); i++) {
            importEquipment(i, type, excelSheetList, map);
            // 使用redis 缓存优先  参量数据缓存到redis
            importDataParamInfo(i, excelSheetList, map, type);
        }
        // 获取要保存的数据
        List<ExcelEquipmentDTO> toSaveBatch = redis.listAllExcelEquipmentBase();
        // 保存数据 key: 设备名称 value: 设备信息
        // 获取导入错误信息
        ExcelResultVO excelResultVO = redis.getExcelResult(userId);
        excelResultVO.setSuccessCount(toSaveBatch.size());
        if (CollUtil.isNotEmpty(toSaveBatch)) {
            toSaveEquipment(toSaveBatch);
        }
        return excelResultVO;
    }

    @Async
    public void toSaveEquipment(List<ExcelEquipmentDTO> toSaveBatch) {
        Map<String, EquipmentInfoDTO> mapEquipmentName = excelClient.importExcelEquipment(toSaveBatch);
        // 对已经封装好的参量 持久化操作
        toImportDataParam(mapEquipmentName);
        redis.deleteRedisCleanAll();
    }

    /**
     * 导入基础设备 redis 缓存版
     *
     * @param target         目标
     * @param type           类型
     * @param excelSheetList Excel 工作表列表
     * @param map            地图
     */
    private void importEquipment(int target,
                                 DataParamImportEnum type,
                                 List<ExcelSheetVO> excelSheetList,
                                 Map<Class<?>, List<?>> map) {
        if (excelSheetList.get(target).getClazz().equals(ExcelEquipmentVO.class)) {
            // 需要导入的设备
            List<ExcelEquipmentVO> equipmentExcelList = BeanUtils.copyToList(map.get(ExcelEquipmentVO.class), ExcelEquipmentVO.class);
            validateDuplicateName1(equipmentExcelList);
            List<ExcelEquipmentDTO> excelEquipmentList = cleanEquipment(type, equipmentExcelList);
            // 缓存设备的基础数据
            redis.setAllExcelEquipmentBase(excelEquipmentList);
        }
        if (excelSheetList.get(target).getClazz().equals(ExcelEquipmentLabelVO.class)) {
            List<ExcelEquipmentLabelVO> equipmentLabelExcelList =
                    BeanUtils.copyToList(map.get(ExcelEquipmentLabelVO.class), ExcelEquipmentLabelVO.class);

        }
        if (excelSheetList.get(target).getClazz().equals(EquipmentModelParamExcelVO.class)) {
            List<EquipmentModelParamExcelVO> equipmentModelParamList =
                    BeanUtils.copyToList(map.get(EquipmentModelParamExcelVO.class), EquipmentModelParamExcelVO.class);
            if (CollUtil.isNotEmpty(equipmentModelParamList)){
                setAllRedisKey4Param(equipmentModelParamList);
            }
        }
    }

    /**
     * 导入设备 (通过模版的设备) Excel
     *
     * @param type           {@link DataParamImportEnum} 导入类型
     * @param map            {@link Map} 数据
     * @param excelSheetList {@link List<  ExcelSheetVO  >} Excel工作表列表
     * @return {@link Boolean}
     */
    @Override
    public ExcelResultVO importEquipmentModelExcel(DataParamImportEnum type,
                                                   Map<Class<?>, List<?>> map,
                                                   List<ExcelSheetVO> excelSheetList) {
        redis.deleteRedisCleanAll();
        Long userId = LocalHolder.getCurrentUser().getUserId();
        for (int i = 0; i < excelSheetList.size(); i++) {
            importEquipmentModel(i, type, excelSheetList, map);
        }
        // 获取要保存的数据
        List<ExcelEquipmentDTO> toSaveBatch = redis.listAllExcelEquipmentBase();
        // 获取导入错误信息
        ExcelResultVO excelResultVO = redis.getExcelResult(userId);
        if (CollUtil.isNotEmpty(toSaveBatch)) {
            Map<String, EquipmentInfoDTO> mapEquipmentName = excelClient.importExcelEquipment(toSaveBatch);
            // 对已经封装好的参量 持久化操作
            toImportDataParamModel(mapEquipmentName);
            excelResultVO.setSuccessCount(mapEquipmentName.keySet().size());
        } else {
            excelResultVO.setSuccessCount(0);
        }
//        redis.deleteRedisCleanAll();
        return excelResultVO;
    }





    private void importInstrument(int target, List<ExcelSheetVO> excelSheetList, Map<Class<?>, List<?>> map) {
        if (excelSheetList.get(target).getClazz().equals(ExcelInstrumentVO.class)) {
            // 设备的基础数据
            List<ExcelInstrumentVO> instrumentExcelList =
                    BeanUtils.copyToList(map.get(ExcelInstrumentVO.class), ExcelInstrumentVO.class);
            validateDuplicateName(instrumentExcelList);
            List<ExcelInstrumentDTO> instrumentList = cleanInstrument(instrumentExcelList);
            // 缓存设备的基础数据
            redis.setAllExcelInstrument(instrumentList);
        }
        if (excelSheetList.get(target).getClazz().equals(ExcelInstrumentReportVO.class)) {
            List<ExcelInstrumentReportVO> instrumentReportExcelList =
                    BeanUtils.copyToList(map.get(ExcelInstrumentReportVO.class), ExcelInstrumentReportVO.class);
            setAllRedisKey4InstrumentReport(instrumentReportExcelList);
        }
    }

    private void setAllRedisKey4InstrumentReport(List<ExcelInstrumentReportVO> instrumentReportExcelList) {
        Map<String, List<ExcelInstrumentReportVO>> result = instrumentReportExcelList.stream()
                .collect(Collectors.groupingBy(ExcelInstrumentReportVO::getInstrumentName, Collectors.toList()));
        for (Map.Entry<String, List<ExcelInstrumentReportVO>> entry : result.entrySet()) {
            List<ExcelInstrumentReportDTO> excelParamDTOS = BeanUtils.copyToList(entry.getValue(), ExcelInstrumentReportDTO.class);
            redis.setRedisKey4InstrumentReportList(entry.getKey(), excelParamDTOS);
        }
    }




    /**
     * 导入设备  (通过模版的设备) Excel new redis 缓存版
     *
     * @param target         目标
     * @param type           类型
     * @param excelSheetList Excel 工作表列表
     * @param map            地图
     */
    private void importEquipmentModel(int target, DataParamImportEnum type, List<ExcelSheetVO> excelSheetList, Map<Class<?>, List<?>> map) {
        if (excelSheetList.get(target).getClazz().equals(ExcelModelRelationEquipmentVO.class)) {
            // 设备的基础数据
            List<ExcelModelRelationEquipmentVO> equipmentExcelList =
                    BeanUtils.copyToList(map.get(ExcelModelRelationEquipmentVO.class), ExcelModelRelationEquipmentVO.class);
            validateDuplicateName2(equipmentExcelList);
            List<ExcelEquipmentDTO> equipmentExcelDTOList = cleanEquipmentByModel(type, equipmentExcelList);
            // 缓存设备的基础数据
            redis.setAllExcelEquipmentBase(equipmentExcelDTOList);
        }
        if (excelSheetList.get(target).getClazz().equals(ExcelEquipmentLabelVO.class)) {
            List<ExcelEquipmentLabelVO> equipmentLabelExcelList =
                    BeanUtils.copyToList(map.get(ExcelEquipmentLabelVO.class), ExcelEquipmentLabelVO.class);

        }
        if (excelSheetList.get(target).getClazz().equals(EquipmentModelParamExcelVO.class)) {
            List<EquipmentModelParamExcelVO> equipmentModelParamList =
                    BeanUtils.copyToList(map.get(EquipmentModelParamExcelVO.class), EquipmentModelParamExcelVO.class);
            if (CollUtil.isNotEmpty(equipmentModelParamList)){
                setAllRedisKey4Param(equipmentModelParamList);
            }
        }
    }

    private void validateDuplicateModelName(List<ExcelModelVO> modelList) {
        Assert.notNull(modelList, "当前没有模型导入");
        Assert.isTrue(!modelList.isEmpty(), "当前没有模型导入");
        List<String> nameList = modelList.stream().map(ExcelModelVO::getName).collect(Collectors.toList());
        Assert.notNull(nameList, "当前没有模型导入");
        List<String> distinctNameList = nameList.stream().distinct().collect(Collectors.toList());
        Assert.isTrue(distinctNameList.size() == nameList.size(), "存在重复的模型名称");
        List<String> collect = distinctNameList.stream().filter(item -> StrUtil.isBlank(item)).collect(Collectors.toList());
        Assert.isTrue(collect.isEmpty(), "存在没用定义名称的模型");
    }

    private void validateDuplicateName(List<ExcelInstrumentVO> instrumentExcelList) {
        Assert.notNull(instrumentExcelList, "当前没有测量器具导入");
        Assert.isTrue(!instrumentExcelList.isEmpty(), "当前没有测量器具导入");
        List<String> nameList = instrumentExcelList.stream().map(ExcelInstrumentVO::getInstrumentName).collect(Collectors.toList());
        Assert.notNull(nameList, "当前没有测量器具导入");
        List<String> distinctNameList = nameList.stream().distinct().collect(Collectors.toList());
        Assert.isTrue(distinctNameList.size() == nameList.size(), "存在重复的测量器具名称");
        List<String> collect = distinctNameList.stream().filter(StrUtil::isBlank).collect(Collectors.toList());
        Assert.isTrue(collect.isEmpty(), "存在没用定义名称的测量器具");
    }

    /**
     * 验证重复名称
     *
     * @param equipmentExcelList 设备Excel列表
     */
    private void validateDuplicateName1(List<ExcelEquipmentVO> equipmentExcelList) {
        Assert.notNull(equipmentExcelList, "当前没有设备导入");
        Assert.isTrue(!equipmentExcelList.isEmpty(), "当前没有设备导入");
        List<String> nameList = equipmentExcelList.stream().map(ExcelEquipmentVO::getName).collect(Collectors.toList());
        Assert.notNull(nameList, "当前没有设备导入");
        List<String> distinctNameList = nameList.stream().distinct().collect(Collectors.toList());
        Assert.isTrue(distinctNameList.size() == nameList.size(), "存在重复的设备名称");
        List<String> collect = distinctNameList.stream().filter(StrUtil::isBlank).collect(Collectors.toList());
        Assert.isTrue(collect.isEmpty(), "存在没用定义名称的设备");
    }

    private void validateDuplicateName2(List<ExcelModelRelationEquipmentVO> equipmentExcelList) {
        Assert.notNull(equipmentExcelList, "当前没有设备导入");
        Assert.isTrue(!equipmentExcelList.isEmpty(), "当前没有设备导入");
        List<String> nameList = equipmentExcelList.stream().map(ExcelModelRelationEquipmentVO::getName).collect(Collectors.toList());
        Assert.notNull(nameList, "当前没有设备导入");
        List<String> distinctNameList = nameList.stream().distinct().collect(Collectors.toList());
        Assert.isTrue(distinctNameList.size() == nameList.size(), "存在重复的设备名称");
        List<String> collect = distinctNameList.stream().filter(StrUtil::isBlank).collect(Collectors.toList());
        Assert.isTrue(collect.isEmpty(), "存在没用定义名称的设备");
    }

    /**
     * 清洗出可以导入的模型
     *
     * @param modelList 模型列表
     * @return {@link List}<{@link ExcelModelDTO}>
     */
    private List<ExcelModelDTO> cleanModel(DataParamImportEnum type, List<ExcelModelVO> modelList) {
        // 清洗掉与数据库重名的设备
        cleanModelByName(type, modelList);
        // 将本次导入的所有设备的 需要校验替换id的数据都缓存redis中
        setAllRedisKey4CodeRuleModel(type, modelList);
        // 清洗出可以导入的最终数据
        return list2ExcelModel(type, modelList);
    }

    /**
     * 清洗出可以导入的最终数据
     *
     * @param instrumentExcelList 测量器具 Excel 列表
     * @return {@link List}<{@link ExcelInstrumentDTO}>
     */
    private List<ExcelInstrumentDTO> cleanInstrument(List<ExcelInstrumentVO> instrumentExcelList) {
        // 清洗掉与数据库重名的设备
        cleanInstrumentByName(instrumentExcelList);
        // 清洗出可以导入的最终数据
        return BeanUtils.copyToList(instrumentExcelList, ExcelInstrumentDTO.class);
    }

    /**
     * 清洗出可以导入的最终数据
     *
     * @param type          类型
     * @param equipmentList 设备清单
     * @return {@link List}<{@link ExcelEquipmentDTO}>
     */
    private List<ExcelEquipmentDTO> cleanEquipment(DataParamImportEnum type, List<ExcelEquipmentVO> equipmentList) {
        // 清洗掉与数据库重名的设备
        cleanEquipmentByName(type, equipmentList);
        // 清洗
        Map<String, DeviceAreaResponseVO> areaDTOMap = cleanEquipmentByAreaName(type, equipmentList);
        // 将本次导入的所有设备的 需要校验替换id的数据都缓存redis中
        setAllRedisKey4CodeRule(type, equipmentList);
        // 清洗出可以导入的最终数据
        return list2ExcelEquipment(type, equipmentList, areaDTOMap);
    }

    /**
     * 清洗出可以导入的最终数据
     *
     * @param type          类型
     * @param equipmentList 设备清单
     * @return {@link List}<{@link ExcelEquipmentDTO}>
     */
    private List<ExcelEquipmentDTO> cleanEquipmentByModel(DataParamImportEnum type, List<ExcelModelRelationEquipmentVO> equipmentList) {
        // 清洗掉与数据库重名的设备
        cleanEquipmentModelRelationByName(type, equipmentList);
        // 清洗掉数据库模版不匹配的设备
        cleanEquipmentByModelName(type, equipmentList);
        // 清洗
        Map<String, DeviceAreaResponseVO> areaDTOMap = cleanEquipmentModelRelationByAreaName(type, equipmentList);
        // 清洗出可以导入的最终数据
        return list2ExcelEquipmentModelRelation(type, equipmentList, areaDTOMap);
    }



    /**
     * 设置所有 Redis Key4 参数
     *
     * @param equipmentModelParamList 设备型号参数列表
     */
    private void setAllRedisKey4Param(List<EquipmentModelParamExcelVO> equipmentModelParamList) {
        Map<String, List<EquipmentModelParamExcelVO>> result = equipmentModelParamList.stream()
                .collect(Collectors.groupingBy(EquipmentModelParamExcelVO::getModelName, Collectors.toList()));
        for (Map.Entry<String, List<EquipmentModelParamExcelVO>> entry : result.entrySet()) {
            List<ExcelParamDTO> excelParamDTOS = BeanUtils.copyToList(entry.getValue(), ExcelParamDTO.class);
            redis.setRedisKey4ParamList(entry.getKey(), excelParamDTOS);
        }
    }

    private CodeProperty codeProperty;
    private DataParamEquipmentExtendService dataParamEquipmentExtendService;

    /**
     * 清洗出可以导入的最终数据
     *
     * @param modelList 模型清单
     * @return {@link List}<{@link ExcelModelDTO}>
     */
    private List<ExcelModelDTO> list2ExcelModel(DataParamImportEnum type, List<ExcelModelVO> modelList) {
        List<ExcelModelDTO> result = new ArrayList<>();
        modelList.forEach(item -> {
            ExcelModelDTO excelModelDTO = BeanUtils.copyToObject(item, ExcelModelDTO.class);
            // 构建规则
            Boolean b = redis.buildRule(type, item, excelModelDTO, excelModelDTO.getName());
            if (b) {
                String code = dataParamEquipmentExtendService.queryCodeBycode(codeProperty.getModelCodeRule(), null);
                excelModelDTO.setCode(code);
                excelModelDTO.setIsMeasuringPointDevice(type.getCodeRuleTypeEnum().checkType(CodeRuleTypeEnum.METER.getType()));
                excelModelDTO.setModel(item.getModel());
                result.add(excelModelDTO);
            }
        });
        return result;
    }



    /**
     * 清洗出可以导入的最终数据
     *
     * @param equipmentList 设备清单
     * @return {@link List}<{@link EquipmentExcelDTO}>
     */
    private List<ExcelEquipmentDTO> list2ExcelEquipment(DataParamImportEnum type,
                                                        List<ExcelEquipmentVO> equipmentList,
                                                        Map<String, DeviceAreaResponseVO> areaDTOMap) {
        List<ExcelEquipmentDTO> result = new ArrayList<>();
        equipmentList.forEach(item -> {
            ExcelEquipmentDTO equipmentExcelDTO = BeanUtils.copyToObject(item, ExcelEquipmentDTO.class);
            // 设置区域id
            if (areaDTOMap.containsKey(item.getAreaName())) {
                equipmentExcelDTO.setAreaId(areaDTOMap.get(item.getAreaName()).getId());
            }

            // 构建规则
            Boolean b = redis.buildRule(type, item, equipmentExcelDTO, equipmentExcelDTO.getName());
            if (b) {
                equipmentExcelDTO.setIsMeasuringPointDevice(type.getCodeRuleTypeEnum().checkType(CodeRuleTypeEnum.METER.getType()));
                result.add(equipmentExcelDTO);
            }
        });
        return result;
    }

    /**
     * 清洗出可以导入的最终数据
     *
     * @param equipmentList 设备清单
     * @return {@link List}<{@link EquipmentExcelDTO}>
     */
    private List<ExcelEquipmentDTO> list2ExcelEquipmentModelRelation(DataParamImportEnum type,
                                                                     List<ExcelModelRelationEquipmentVO> equipmentList,
                                                                     Map<String, DeviceAreaResponseVO> areaDTOMap) {
        return equipmentList.stream().map(item -> {
            ExcelEquipmentDTO equipmentExcelDTO = BeanUtils.copyToObject(item, ExcelEquipmentDTO.class);
            ModelInfoDTO model = redis.getModelInfoByModelName(item.getModelName());
            // 设置区域id
            if (areaDTOMap.containsKey(item.getAreaName())) {
                equipmentExcelDTO.setAreaId(areaDTOMap.get(item.getAreaName()).getId());
            }
            // 保存模型信息
            setCodeRule(model, equipmentExcelDTO);
            equipmentExcelDTO.setIsMeasuringPointDevice(type.getCodeRuleTypeEnum().checkType(CodeRuleTypeEnum.METER.getType()));
            return equipmentExcelDTO;
        }).collect(Collectors.toList());
    }

    private void setCodeRule(ModelInfoDTO model, ExcelNormalCodeRuleDTO dto) {
        dto.setEquipmentCodeRule(model.getEquipmentCodeRule());
        dto.setRuleTableData(model.getRuleTableData());
        dto.setRuleName(model.getRuleName());
        dto.setEnergyClassificationId(model.getEnergyClassificationId());
        dto.setEnergyClassification(model.getEnergyClassification());
        dto.setBrand(model.getBrand());
        dto.setModel(model.getModel());
        dto.setType(model.getType());
        dto.setTypeId(model.getTypeId());
    }

    /**
     * 按模型名称 清洗掉数据库中没有匹配模版的设备
     *
     * @param type          类型
     * @param equipmentList 设备清单
     */
    private void cleanEquipmentByModelName(DataParamImportEnum type, List<ExcelModelRelationEquipmentVO> equipmentList) {
        List<String> modelNameList = equipmentList.stream().map(ExcelModelRelationEquipmentVO::getModelName).collect(Collectors.toList());
        Map<String, ModelInfoDTO> mapEquipmentModel = equipmentModelService.mapModelByNameList(type, modelNameList);
        if (!mapEquipmentModel.keySet().isEmpty()) {
            // 记录导入设备模型不存在问题
            Map<String, String> noExistEquipmentModelMap = equipmentList.stream()
                    .filter(item -> !mapEquipmentModel.containsKey(item.getModelName()))
                    .collect(Collectors.toMap(ExcelModelRelationEquipmentVO::getName, ExcelModelRelationEquipmentVO::getModelName));
            if (!noExistEquipmentModelMap.isEmpty()) {
                // 记录导入设备模型不存在问题
                ExcelResultVO excelResultVO = new ExcelResultVO();
                excelResultVO.setNoExistEquipmentModelMessage(noExistEquipmentModelMap);
                redis.setExcelResult(excelResultVO);
            }
            // 排除掉模版不在数据库里的设备
            equipmentList.removeIf(item -> !mapEquipmentModel.containsKey(item.getModelName()));
            Assert.isTrue(!equipmentList.isEmpty(), "存在没有匹配模版的设备");
        }

        // 清洗出可以导入的最终数据参量信息， 并且设置规则
        Map<String, String> equipmentModelMap = equipmentList.stream()
                .collect(Collectors.toMap(ExcelModelRelationEquipmentVO::getName,
                        ExcelModelRelationEquipmentVO::getModelName));
        // 缓存设备模型
        redis.setAllModelByEquipmentName(equipmentModelMap, mapEquipmentModel);
    }

    private Map<String, DeviceAreaResponseVO> cleanEquipmentByAreaName(DataParamImportEnum type, List<ExcelEquipmentVO> equipmentList) {
        Map<String, String> mapEquipmentAreaName = equipmentList.stream()
                .collect(Collectors.toMap(ExcelEquipmentVO::getName, ExcelEquipmentVO::getAreaName));

        Map<String, DeviceAreaResponseVO> tempMap = deviceAreaService.mapDeviceAreaByNameList(BeanUtils.copyToList(mapEquipmentAreaName.values(),String.class));
        Assert.isTrue(!tempMap.isEmpty(), "存在没有匹配区域的设备");

        Map<String, String> errorMap = equipmentList.stream().filter(item -> !tempMap.containsKey(item.getAreaName()))
                .collect(Collectors.toMap(ExcelEquipmentVO::getName, ExcelEquipmentVO::getAreaName));

        equipmentList.removeIf(item -> !tempMap.containsKey(item.getAreaName()));

        if (!errorMap.isEmpty()) {
            // 记录导入设备区域不存在问题
            ExcelResultVO excelResultVO = new ExcelResultVO();
            excelResultVO.setNoExistEquipmentAreaMessage(errorMap);
            redis.setExcelResult(excelResultVO);
        }
        return tempMap;
    }

    private Map<String, DeviceAreaResponseVO> cleanEquipmentModelRelationByAreaName(DataParamImportEnum type, List<ExcelModelRelationEquipmentVO> equipmentList) {
        Map<String, String> mapEquipmentAreaName = equipmentList.stream()
                .collect(Collectors.toMap(ExcelModelRelationEquipmentVO::getName, ExcelModelRelationEquipmentVO::getAreaName));

        Map<String, DeviceAreaResponseVO> tempMap = deviceAreaService.mapDeviceAreaByNameList(BeanUtils.copyToList(mapEquipmentAreaName.values(),String.class));
        Assert.isTrue(!tempMap.isEmpty(), "存在没有匹配区域的设备");

        Map<String, String> errorMap = equipmentList.stream().filter(item -> !tempMap.containsKey(item.getAreaName()))
                .collect(Collectors.toMap(ExcelModelRelationEquipmentVO::getName, ExcelModelRelationEquipmentVO::getAreaName));

        equipmentList.removeIf(item -> !tempMap.containsKey(item.getAreaName()));

        if (!errorMap.isEmpty()) {
            // 记录导入设备区域不存在问题
            ExcelResultVO excelResultVO = new ExcelResultVO();
            excelResultVO.setNoExistEquipmentAreaMessage(errorMap);
            redis.setExcelResult(excelResultVO);
        }
        return tempMap;
    }


    /**
     * 按名称 清洗掉数据库中已经有的设备
     *
     * @param type                       类型
     * @param equipmentModelRelationList 设备清单
     */
    private void cleanEquipmentModelRelationByName(DataParamImportEnum type,
                                                   List<ExcelModelRelationEquipmentVO> equipmentModelRelationList) {
        List<String> nameList = equipmentModelRelationList.stream()
                .map(ExcelModelRelationEquipmentVO::getName).collect(Collectors.toList());
        List<String> cleanNameList = cleanEquipmentByNameBase(type, nameList);
        Assert.isTrue(!cleanNameList.isEmpty(), "所有设备均已存在，不可重复导入");
        equipmentModelRelationList.removeIf(item -> !cleanNameList.contains(item.getName()));

        List<String> dockIdentifierList = equipmentModelRelationList.stream()
                .map(ExcelModelRelationEquipmentVO::getDockIdentifier).collect(Collectors.toList());
        List<String> cleanIdentifierList = cleanEquipmentByDockIdentifierBase(type, dockIdentifierList);
        Assert.isTrue(!cleanIdentifierList.isEmpty(), "所有设备均已存在，不可重复导入");
        equipmentModelRelationList.removeIf(item -> !cleanIdentifierList.contains(item.getDockIdentifier()));
    }


    private void cleanInstrumentByName(List<ExcelInstrumentVO> instrumentExcelList) {
        List<String> nameList = instrumentExcelList.stream()
                .map(ExcelInstrumentVO::getInstrumentName).collect(Collectors.toList());
        Map<String, ResponseInstrumentDTO> mapDuplicate = instrumentBiz.mapInstrumentByNameList(nameList);
        if (!mapDuplicate.keySet().isEmpty()) {
            nameList.removeIf(mapDuplicate::containsKey);
            // 记录重名的设备名称
            ExcelResultVO resultVO = new ExcelResultVO();
            resultVO.setDuplicateMessage(String.join(StrUtil.COMMA, mapDuplicate.keySet()));
            redis.setExcelResult(resultVO);
        }
        Assert.isTrue(!nameList.isEmpty(), "所有测量器具均已存在，不可重复导入");
    }

    /**
     * 按名称 清洗掉数据库中已经有的设备
     *
     * @param type          类型
     * @param equipmentList 设备清单
     */
    private void cleanEquipmentByName(DataParamImportEnum type,
                                      List<ExcelEquipmentVO> equipmentList) {
        List<String> nameList = equipmentList.stream()
                .map(ExcelEquipmentVO::getName).collect(Collectors.toList());
        List<String> cleanList = cleanEquipmentByNameBase(type, nameList);
        Assert.isTrue(!cleanList.isEmpty(), "所有设备均已存在，不可重复导入");
        equipmentList.removeIf(item -> !cleanList.contains(item.getName()));

        List<String> dockIdentifierList = equipmentList.stream()
                .map(ExcelEquipmentVO::getDockIdentifier).collect(Collectors.toList());
        List<String> cleanIdentifierList = cleanEquipmentByDockIdentifierBase(type, dockIdentifierList);
        Assert.isTrue(!cleanIdentifierList.isEmpty(), "所有设备均已存在，不可重复导入");
        equipmentList.removeIf(item -> !cleanIdentifierList.contains(item.getDockIdentifier()));
    }

    /**
     * 清洗掉数据库中已经有的设备模版
     *
     * @param type      类型
     * @param modelList 模版清单
     */
    private void cleanModelByName(DataParamImportEnum type, List<ExcelModelVO> modelList) {
        List<String> nameList = modelList.stream()
                .map(ExcelModelVO::getName).collect(Collectors.toList());
        List<String> cleanList = cleanModelByNameBase(type, nameList);
        Assert.isTrue(!cleanList.isEmpty(), "所有设备模型均已存在，不可重复导入");
        modelList.removeIf(item -> !cleanList.contains(item.getName()));
    }

    private List<String> cleanModelByNameBase(DataParamImportEnum type, List<String> nameList) {
        Map<String, ModelInfoDTO> mapDuplicate = equipmentModelService.mapModelByNameList(type, nameList);
        if (!mapDuplicate.keySet().isEmpty()) {
            nameList.removeIf(mapDuplicate::containsKey);
            // 记录重名的设备名称
            ExcelResultVO resultVO = new ExcelResultVO();
            resultVO.setDuplicateMessage(String.join(StrUtil.COMMA, mapDuplicate.keySet()));
            redis.setExcelResult(resultVO);
        }
        return nameList;
    }

    private List<String> cleanEquipmentByNameBase(DataParamImportEnum type, List<String> nameList) {
        Map<String, EquipmentInfoDTO> mapDuplicate = equipmentInfoExtraService.mapEquipmentByNameList(type, nameList);
        if (!mapDuplicate.keySet().isEmpty()) {
            nameList.removeIf(mapDuplicate::containsKey);
            // 记录重名的设备名称
            ExcelResultVO resultVO = new ExcelResultVO();
            resultVO.setDuplicateMessage(String.join(StrUtil.COMMA, mapDuplicate.keySet()));
            redis.setExcelResult(resultVO);
        }
        return nameList;
    }

    private List<String> cleanEquipmentByDockIdentifierBase(DataParamImportEnum type, List<String> dockIdentifierList) {
        Map<String, EquipmentInfoDTO> mapDuplicate = equipmentInfoExtraService.mapEquipmentByDockIdentifierList(type, dockIdentifierList);
        if (!mapDuplicate.keySet().isEmpty()) {
            dockIdentifierList.removeIf(mapDuplicate::containsKey);
            // 记录重名的设备名称
            ExcelResultVO resultVO = new ExcelResultVO();
            resultVO.setDuplicateMessage(String.join(StrUtil.COMMA, mapDuplicate.keySet()));
            redis.setExcelResult(resultVO);
        }
        return dockIdentifierList;
    }


    public static final String ENERGY = "能源分类#";
    public static final String BRAND = "设备品牌#";
    public static final String TYPE = "设备分类#";
    public static final String MODEL = "设备型号#";

    /**
     * 设置所有 Redis Key 设备模版 检索替换
     *
     * @param type          类型
     * @param equipmentList 设备清单
     */
    private void setAllRedisKey4CodeRuleModel(DataParamImportEnum type, List<ExcelModelVO> equipmentList) {
        // 规则字典名称
        List<String> ruleDictNameList = new ArrayList<>();
        // 能源分类名称
        equipmentList.forEach(item -> {
            // 能源
            if (StrUtil.isNotBlank(item.getEnergyClassification())) {
                ruleDictNameList.add(ENERGY + item.getEnergyClassification().trim());
            }
            // 品牌
            if (StrUtil.isNotBlank(item.getBrand())) {
                ruleDictNameList.add(BRAND + item.getBrand().trim());
            }
            // 类型
            if (StrUtil.isNotBlank(item.getType())) {
                ruleDictNameList.add(TYPE + item.getType().trim());
            }
            // 型号
            if (StrUtil.isNotBlank(item.getModel())) {
                ruleDictNameList.add(MODEL + item.getModel().trim());
            }
        });
        // 设置所有规则字典
        redis.setAllRuleDictByName(type, ruleDictNameList);
    }

    /**
     * 设置所有 Redis Key 设备模版 检索替换
     *
     * @param type          类型
     * @param equipmentList 设备清单
     */
    private void setAllRedisKey4CodeRule(DataParamImportEnum type, List<ExcelEquipmentVO> equipmentList) {
        // 规则字典名称
        List<String> ruleDictNameList = new ArrayList<>();
        // 能源分类名称
        equipmentList.forEach(item -> {
            // 能源
            if (StrUtil.isNotBlank(item.getEnergyClassification())) {
                ruleDictNameList.add(ENERGY + item.getEnergyClassification().trim());
            }
            // 品牌
            if (StrUtil.isNotBlank(item.getBrand())) {
                ruleDictNameList.add(BRAND + item.getBrand().trim());
            }
            // 类型
            if (StrUtil.isNotBlank(item.getType())) {
                ruleDictNameList.add(TYPE + item.getType().trim());
            }
            // 型号
            if (StrUtil.isNotBlank(item.getModel())) {
                ruleDictNameList.add(MODEL + item.getModel().trim());
            }
        });
        // 设置所有规则字典
        redis.setAllRuleDictByName(type, ruleDictNameList);
    }

    /**
     * 导入数据参数 temp
     *
     * @param mapModelName 地图模型名称
     */
    private void toImportDataParamTemp(Map<String, ModelDTO> mapModelName, Map<Class<?>, List<?>> map, DataParamImportEnum type) {
        String tenantId = LocalHolder.getCurrentUser().getTenantId();
        for (String modelName : mapModelName.keySet()) {
            List<DataParamTempDTO> dataParamTempList = new ArrayList<>();

            List<AlgorithmExcelVO> algorithmExcelList = (List<AlgorithmExcelVO>) map.get(AlgorithmExcelVO.class);
            List<ExcelLabelVO> labelExcelList = (List<ExcelLabelVO>) map.get(ExcelLabelVO.class);
            List<ExcelAlarmVO> alarmExcelList = (List<ExcelAlarmVO>) map.get(ExcelAlarmVO.class);
            List<ExcelDataParamVO> dataParamExcelList = (List<ExcelDataParamVO>) map.get(ExcelDataParamVO.class);

            // 获取已经从excel 中获取的封装好的参量信息
            if (CollUtil.isNotEmpty(dataParamExcelList)) {
                Map<String, List<String>> dataParamMap = dataParamExcelList.stream()
                        .collect(Collectors.groupingBy(ExcelDataParamVO::getRelationName,
                                Collectors.mapping(ExcelDataParamVO::getName, Collectors.toList())));
                List<String> paramNameList = dataParamMap.get(modelName);
                List<DataParamTempDTO> dataParamTempDTOS = redis.listDataParamTempByParamName(paramNameList);
                dataParamTempList.addAll(dataParamTempDTOS);
            }
            //获取算法
            if (CollUtil.isNotEmpty(algorithmExcelList)){
                List<String> algorithmName = algorithmExcelList.stream()
                        .filter(dto -> dto.getDataParamName().contains(modelName))
                        .map(AlgorithmExcelVO::getDataParamName)
                        .collect(Collectors.toList());
                Map<String, AlgorithmTempDTO> algorithmTempDTOMap = redis.listAlgorithmTempByParamName(algorithmName);
                //设置算法
                for (DataParamTempDTO dataParamTempDTO : dataParamTempList){
                    for (String key : algorithmTempDTOMap.keySet()){
                        if (key.contains(dataParamTempDTO.getName())){
                            AlgorithmTempDTO algorithmTempDTO = algorithmTempDTOMap.get(key);
                            dataParamTempDTO.setAlgorithm(algorithmTempDTO);
                        }
                    }
                }
            }
            //获取报警信息
            if (CollUtil.isNotEmpty(alarmExcelList)) {
                List<String> alarmName = alarmExcelList.stream()
                        .map(ExcelAlarmVO::getDataParamName)
                        .collect(Collectors.toList());
                Map<String, List<AlarmTempDTO>> alarmTempDTOMap = redis.listAlarmTempByParamName(alarmName);
                for (DataParamTempDTO dataParamTempDTO : dataParamTempList) {
                    for (String key : alarmTempDTOMap.keySet()) {
                        if (key.equals(dataParamTempDTO.getName())) {
                            dataParamTempDTO.setAlarmList(alarmTempDTOMap.get(key));
                        }
                    }
                }
            }

            if (CollUtil.isNotEmpty(dataParamTempList)) {
                ModelDTO modelDTO = mapModelName.get(modelName);
                dataParamTempList.forEach(item -> {
                    if (type.equals(DataParamImportEnum.MODEL)) {
                        item.setRelationType(2);
                    }
                    if (type.equals(DataParamImportEnum.METER_MODEL)) {
                        item.setRelationType(4);
                    }
                    item.setRelationId(modelDTO.getId());
                });
            }
            dataParamTempService.importDataParamDTO(tenantId, dataParamTempList);
        }
    }

    /**
     * 导入数据参数性能
     *
     * @param mapEquipmentName 地图设备名称
     */
    private void toImportDataParam(Map<String, EquipmentInfoDTO> mapEquipmentName) {
        List<DataParamTempVO> result = new ArrayList<>();
        for (String equipmentName : mapEquipmentName.keySet()) {
            // 获取已经从excel 中获取的封装好的参量信息
            List<DataParamTempDTO> dataParamTempList = redis.listDataParamTempByEquipmentName(equipmentName);
            if (CollUtil.isEmpty(dataParamTempList)) {
                continue;
            }
            result.addAll(toBuildDataParamTemp(dataParamTempList, mapEquipmentName.get(equipmentName)));
        }
        // 导入数据参数
        if (CollUtil.isNotEmpty(result)) {
            List<DataParam4EquipmentDTO> list = dataParamService.toDataParam4EquipmentList(result);
            String tenantId = LocalHolder.getCurrentUser().getTenantId();
            dataParamService.importDataParam(tenantId, list);
        }
    }

    /**
     * 导入数据参数性能
     *
     * @param mapEquipmentName 地图设备名称
     */
    private void toImportDataParamModel(Map<String, EquipmentInfoDTO> mapEquipmentName) {
        Set<String> equipmentNameList = mapEquipmentName.keySet();
        Map<String, String> equipmentNameModelNameMap = redis.mapEquipmentNameModelName(equipmentNameList);
        // 导入数据参数
        dataParamService.importDataParamModel(LocalHolder.getCurrentUser(), mapEquipmentName, equipmentNameModelNameMap);
    }

    private List<DataParamTempVO> toBuildDataParamTemp(List<DataParamTempDTO> dataParamTempList,
                                                       EquipmentInfoDTO equipmentInfo) {
        return dataParamTempList.stream().map(item -> {
            DataParamTempVO dataParamTempVO = new DataParamTempVO(item);
            dataParamTempVO.setEquipmentId(equipmentInfo.getId());
            dataParamTempVO.setEquipmentName(equipmentInfo.getName());
            dataParamTempVO.setEquipmentCode(equipmentInfo.getCode());
            return dataParamTempVO;
        }).collect(Collectors.toList());
    }

    private void importDataParamInfo(Integer target, List<ExcelSheetVO> excelSheetList, Map<Class<?>, List<?>> map, DataParamImportEnum type) {
        if (excelSheetList.get(target).getClazz().equals(ExcelDataParamVO.class)) {
            List<ExcelDataParamVO> dataParamExcelList = (List<ExcelDataParamVO>) map.get(ExcelDataParamVO.class);
            if (CollUtil.isNotEmpty(dataParamExcelList)) {
                redis.setDataParamBasePref(dataParamExcelList, type);
            }
        }
        if (excelSheetList.get(target).getClazz().equals(ExcelFrequencyVO.class)) {
            List<ExcelFrequencyVO> frequencyExcelList = (List<ExcelFrequencyVO>) map.get(ExcelFrequencyVO.class);
            if (CollUtil.isNotEmpty(frequencyExcelList)) {
                redis.setFrequencyExcel(frequencyExcelList);
            }
        }
        if (excelSheetList.get(target).getClazz().equals(AlgorithmExcelVO.class)) {
            List<AlgorithmExcelVO> algorithmExcelList = (List<AlgorithmExcelVO>) map.get(AlgorithmExcelVO.class);
            if (CollUtil.isNotEmpty(algorithmExcelList)) {
                redis.setAlgorithmExcel(algorithmExcelList);
            }
        }
        if (excelSheetList.get(target).getClazz().equals(ExcelAlgorithmParamVO.class)) {
            List<ExcelAlgorithmParamVO> algorithmParamExcelList = (List<ExcelAlgorithmParamVO>) map.get(ExcelAlgorithmParamVO.class);
            if (CollUtil.isNotEmpty(algorithmParamExcelList)) {
                redis.setAlgorithmParamExcel(algorithmParamExcelList);
            }
        }
        if (excelSheetList.get(target).getClazz().equals(ExcelLabelVO.class)) {
            List<ExcelLabelVO> labelExcelList = (List<ExcelLabelVO>) map.get(ExcelLabelVO.class);

        }
        if (excelSheetList.get(target).getClazz().equals(ExcelAlarmVO.class)) {
            List<ExcelAlarmVO> alarmExcelList = (List<ExcelAlarmVO>) map.get(ExcelAlarmVO.class);
            if (CollUtil.isNotEmpty(alarmExcelList)) {
                redis.setAlarmExcel(alarmExcelList);
            }
        }
    }

}
